﻿using System;
using System.Collections.Generic;
using System.IO;

namespace Aeon.Emulator.BiosServices
{
    /// <summary>
    /// Implements BIOS system services.
    /// </summary>
    internal sealed class SystemServices : IInterruptHandler
    {
        private VirtualMachine vm;

        /// <summary>
        /// Initializes a new instance of the <see cref="SystemServices"/> class.
        /// </summary>
        public SystemServices()
        {
        }

        /// <summary>
        /// Gets the interrupts which are handled by this handler.
        /// </summary>
        IEnumerable<InterruptHandlerInfo> IInterruptHandler.HandledInterrupts
        {
            get { return new InterruptHandlerInfo[] { 0x11, 0x15 }; }
        }

        /// <summary>
        /// Called when the interrupt handler should perform its action.
        /// </summary>
        /// <param name="interrupt">Raised interrupt number.</param>
        void IInterruptHandler.HandleInterrupt(int interrupt)
        {
            if(interrupt == 0x11)
            {
                vm.Processor.AX = unchecked((short)0xD426);
                return;
            }

            bool error = false;

            switch(vm.Processor.AH)
            {
            case Functions.GetConfiguration:
                vm.WriteSegmentRegister(SegmentIndex.ES, PhysicalMemory.BiosConfigurationAddress.Segment);
                vm.Processor.BX = (short)PhysicalMemory.BiosConfigurationAddress.Offset;
                vm.Processor.AH = 0;
                break;

            case Functions.GetExtendedMemorySize:
                vm.Processor.AX = 0;
                break;

            default:
                System.Diagnostics.Debug.WriteLine(string.Format("System int 15h command {0:X2} not implemented.", vm.Processor.AH));
                error = true;
                break;
            }
            
            vm.Processor.CarryFlag = error;
            vm.PhysicalMemory.SetUInt16(vm.Processor.SS, (ushort)(vm.Processor.SP + 4), (ushort)vm.Processor.Flags);
        }
        /// <summary>
        /// Invoked when the emulator enters a paused state.
        /// </summary>
        void IVirtualDevice.Pause()
        {
        }
        /// <summary>
        /// Invoked when the emulator resumes from a paused state.
        /// </summary>
        void IVirtualDevice.Resume()
        {
        }
        /// <summary>
        /// Invoked when the virtual device has been added to a VirtualMachine.
        /// </summary>
        /// <param name="vm">VirtualMachine which owns the device.</param>
        void IVirtualDevice.DeviceRegistered(VirtualMachine vm)
        {
            this.vm = vm;
        }
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        void IDisposable.Dispose()
        {
        }
        /// <summary>
        /// Invoked when the device should save its current state to a <see cref="System.IO.Stream"/>.
        /// </summary>
        /// <param name="destination"><see cref="System.IO.Stream"/> to which the state is saved.</param>
        void IVirtualDevice.SaveCurrentState(Stream destination)
        {
        }
        /// <summary>
        /// Invoked when the device should restore its state from a <see cref="System.IO.Stream"/>.
        /// </summary>
        /// <param name="source"><see cref="System.IO.Stream"/> from which the state is restored.</param>
        void IVirtualDevice.RestoreState(Stream source)
        {
        }
    }
}
